' outputpanel.bmx

Strict

Import brl.stream
Import brl.timer
Import pub.freeprocess

Import "host.bmx"
Import "bytebuffer.bmx"
Import "style.bmx"

Const MKEY$=Chr(8)

Type TOutputPanel Extends TToolPanel	'used build and run

	Field	host:THost
	Field	outputstyle:TGadgetStyle
	Field	errstyle:TTextStyle
	Field	hideoutput:TButton
	Field	output:TGadget
	Field	process:TProcess
	Field	processor:TTool
	Field	user$,cmdline$,err$,post$
	Field	outbuffer:TByteBuffer
	Field	errbuffer:TByteBuffer
	Field	pipe:TTextStream
	Field	outputmenu:TGadget
	Field	outputtimer:TTimer
	Field	errlist:TList=New TList

	Method Clear()
		If Not output Open()
		SetTextAreaText output,""
	End Method
	
	Method Write(mess$)
		If Not output Open()
		mess=mess.Replace$(Chr(0),"")
		AddTextAreaText output,mess
	End Method

	Method WriteError(mess$)
		If Not output Open()
		mess=mess.Replace$(Chr(0),"")
		Local p=TextAreaLen(output)
		AddTextAreaText output,mess	
		errstyle.Format output,p,mess.length
	End Method

	Method Execute(owner:TTool,cmd$,mess$="",exe$="",home=True)
		If Not output Open()
		If Not mess$ mess$=cmd$
		err$=""
		post$=exe
		host.SelectPanel Self
		host.debugger.invoke "RESET",Self
		If process And ProcessStatus(process)
			Delay 500
			If ProcessStatus(process)
				Notify "Current process still busy "+cmdline 
				Return
			EndIf
		EndIf
		cmd=cmd.Trim()
		errbuffer=New TByteBuffer
		outbuffer=New TByteBuffer
		processor=owner;
		process=CreateProcess(cmd$,HIDECONSOLE)
		If Not process 
			Notify "Process Failure with "+cmd
			Return
		EndIf
		If Not process.status() 'simon was here
			process=Null
			Notify "Process Failed to start "+cmd
			Return
		EndIf		
		pipe=TTextStream.Create(Process.pipe,TTextStream.UTF8)
		cmdline=cmd
		If home Clear
		Write mess$+"~n"
		host.RefreshToolbar	
	End Method

	Method WritePipe(l$)
		If pipe pipe.WriteLine(l$)
	End Method

	Method Go()
		WritePipe "r"
	End Method
	
	Method StepOver()
		WritePipe "s"
	End Method
	
	Method StepIn()
		WritePipe "e"
	End Method

	Method StepOut()
		WritePipe "l"
	End Method
	
	Method Stop()
'		Local	pipe:TPipeStream
		If Not process Return		
		process.Terminate
		FlushPipes process.pipe,process.err		
		process.Close
		process=Null
		Write "~nProcess terminated~n"
		host.DebugExit
		Close
	End Method
	
	Method Wait()
		While process And process.status()
			PollSystem
		Wend
	End Method
	
	Method Invoke(command$,argument:Object=Null)
		Select command
			Case "SHOW" 
				host.SetTitle ""
				If output ActivateGadget output	
			Case "CLOSE"
				host.RemovePanel Self
				output=Null
			Case "CUT"
				GadgetCut output
			Case "COPY"
				GadgetCopy output
			Case "PASTE"
				GadgetPaste output
			Case "SELECTALL" 
				If output SelectTextAreaText output
			Case "REFRESH"
				outputstyle.apply output
		End Select
	End Method

	Method Escape()
		Stop
		Close
	End Method
	
	Method Close()
		host.SelectPanel host.activepanel
	End Method

' back up dude...

	Method OnEvent()
	
		If EventSource()=output
			If EventID()=EVENT_GADGETMENU
				PopupWindowMenu host.window,outputmenu
				Return
			EndIf
		EndIf

		Global guard

		If process And EventID()=EVENT_TIMERTICK And Not guard
			guard=True
			ReadPipes process.pipe,process.err
			Local status=process.status()	
			If status=0
				process.terminate
				FlushPipes process.pipe,process.err
				process.close
				process=Null
				Write "~nProcess complete~n"
				host.DebugExit
	'			host.SelectPanel Self
				If processor
					processor.process("")
					Local out$=outbuffer.ReadString(outbuffer.readpointer)
					If out processor.process(out)
					processor.process("")
				EndIf	
				If err$ 
					For Local plugin:TPlugin=EachIn host.pluginlist
						err=plugin.Debug(err)
					Next
					If err
						Notify "Unprocessed error:"+err
						err=""
					EndIf							
				Else
					If post$
						Local menuaction=Int(post)
						If menuaction
							host.MainMenu menuaction
						Else				
	'						Execute post$,"","",False,0
						EndIf
					Else
						If hideoutput Close
					EndIf
				EndIf
'				Return
			EndIf	
			guard=False
		EndIf

	End Method
		
	Method FlushPipes(pipe:TPipeStream,errpipe:TPipeStream)
		ReadPipes(pipe,errpipe)
		Local bytes:Byte[]=errbuffer.flushbytes()
		If bytes
			Local line$=String.FromBytes(bytes,Len bytes)
			line=line.Replace$(Chr(13),"")
			If line<>">" Write line
		EndIf
	End Method
		
	Method ReadPipes(pipe:TPipeStream,errpipe:TPipeStream)
		Local	bytes:Byte[],line$
' stdoutput from process goes directly to outputpanel
		bytes=pipe.ReadPipe()
		If bytes
			line$=String.FromBytes(bytes,Len bytes)
			line=line.Replace$(Chr$(13),"")
			Write line
'			log.write bytes
			outbuffer.WriteBytes bytes,Len bytes
'			outlog$:+line
		EndIf
' erroutput from process goes to host.processerror
		bytes=errpipe.ReadPipe()
		If bytes errbuffer.WriteBytes bytes,Len bytes	
		While errbuffer.LineAvail()	
			line$=errbuffer.ReadLine()
			If Not line Continue
			If processor
				line=processor.process(line)
			EndIf
			If line
				line=host.ProcessError(line)
			EndIf
			If line 
				WriteError line+"~n"
				err:+line+"~n"
			EndIf
		Wend

	End Method
	
	Method WriteChar(char)
		Local	pipe:TPipeStream
		If Not process Return		
		pipe=process.pipe
		If char=3			'CTRL-C
			Stop()
		EndIf
		If char=13			'ENTER
'			Write Chr(10)
			pipe.WriteLine user$
			user$=""
		EndIf
		If char=8			'DELETE
			If Len user
'				Local pos=TextAreaLen(output)
'				If pos SetTextAreaText output,"",pos-1,1,TEXTAREA_CHARS
				user=user[..Len user-1]
			EndIf
		EndIf
		If char>31
'			Write Chr(char)
			user:+Chr(char)
		EndIf
	End Method

	Method Open()
		If Not output 
			host.addpanel(Self)		
			output=CreateTextArea(0,0,ClientWidth(panel),ClientHeight(panel),panel,TEXTAREA_WORDWRAP)'TEXTAREA_READONLY)
			SetGadgetLayout output,1,1,1,1
			SetGadgetFilter output,outputfilter,Self
			SetGadgetText output," "	'simon was here		
			outputstyle.apply output
		EndIf
		host.SelectPanel Self
	End Method

	Function outputfilter(event:TEvent,context:Object)
		Local out:TOutputPanel=TOutputPanel(context)
		If Not out Return
		Select event.id
			Case EVENT_KEYDOWN
				If event.data=27
					out.Escape()
					Return 0
				EndIf
			Case EVENT_KEYCHAR
'				Print "output_keychar "+event.data
				out.writechar(event.data)
		End Select
		Return 1
	End Function

	Function CreateOutputMenu:TGadget()
		Local	edit:TGadget
		edit=CreateMenu("&Edit",0,Null)
		CreateMenu "Cu&t"+MKEY+"Ctrl+X",MENUCUT,edit
		CreateMenu "&Copy"+MKEY+"Ctrl+C",MENUCOPY,edit
		CreateMenu "&Paste"+MKEY+"Ctrl+V",MENUPASTE,edit
		CreateMenu "",0,edit
		CreateMenu "Stop"+MKEY+"Alt+X",MENUSTOP,edit
		Return edit
	End Function

	Function Create:TOutputPanel(owner:THost,outputstyle:TGadgetStyle,errstyle:TTextStyle)
		Local	o:TOutputPanel
		o=New TOutputPanel
		o.host=owner	
		o.outputstyle=outputstyle
		o.errstyle=errstyle
		o.name="Output"
		DebugLog "create timer..."
		o.outputtimer=CreateTimer(30)
		o.outputmenu=CreateOutputMenu()
		Return o
	End Function
	
End Type
